package de.umr.fb12.vs.os.uebung;

import static de.umr.fb12.vs.os.Task.STATES.BLOCKED;
import static de.umr.fb12.vs.os.Task.STATES.DEAD;

import java.util.LinkedList;
import java.util.List;

import de.umr.fb12.vs.os.CoreScheduler;
import de.umr.fb12.vs.os.SchedClass;
import de.umr.fb12.vs.os.Task;

public class RRSched implements SchedClass {
	// Runqueue
	private List<Task> run_q = new LinkedList<Task>();
	// RR time quantum
	private final static int quantum = 300;
	// auxiliary variable for quantum
	private long start_time = 0;

	@Override
	public void enqueue_task(Task curr, Task enq) {
		// if a task is enqueued while the idle thread is active:
		// set_tsk_need_resched, so that schedule is executed
		if (curr.isIdle_task())
			curr.set_tsk_need_resched();
		run_q.add(enq);
	}

	@Override
	public void dequeue_task(Task curr, Task deq) {
		// if the task which shall be dequeued is the current:
		// set_tsk_need_resched, so that schedule() is executed
		if (curr == deq)
			curr.set_tsk_need_resched();
		// remove deq from the runqueue note: if curr==deq nothing happens
		run_q.remove(deq);

	}

	@Override
	public void yield_task(Task curr, Task t) {
		// if the current task yields, then call set_tsk_need_resched to
		// call schedule()
		if (curr == t)
			t.set_tsk_need_resched();
	}

	@Override
	public Task pick_next_task() {
		Task next = null;
		// if we are asked for next task and we have one, return it and set the
		// start_time of the task
		if (run_q.size() > 0) {
			start_time = System.currentTimeMillis();
			next = run_q.remove(0);
		}
		return next;
	}

	@Override
	public void put_prev_task(Task prev) {
		// if a task is removed from the CPU and is not dead or blocked put it
		// back to the runqueue.
		if (prev.getState() != BLOCKED && prev.getState() != DEAD) {
			run_q.add(prev);
		}

	}

	@Override
	public void task_tick(Task curr) {
		// if we have a other task than the running and its time slice is up,
		// set it to reschedule
		if (run_q.size() > 0
				&& System.currentTimeMillis() > start_time + quantum
				&& curr.getSchedclass() == this)
			curr.set_tsk_need_resched();
	}

	@Override
	public void task_new(Task curr, Task newtsk) {
		// no magic here, just add new task to our queue
		run_q.add(newtsk);
	}

	public static void main(String[] args) {
		// create a instance of this class
		RRSched rrSched = new RRSched();
		CoreScheduler.setVerbose(true);
		// Initialize the CoreScheduler with this SchedulerClass and pass init
		// task and worker task sources.
		CoreScheduler.init(rrSched, "asm/simple_init.asm",
				"asm/simple_dummy.asm");
	}
}
